home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / common / emailaccount.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  20KB  |  538 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from common import AccountBase, profile, netcall, pref, UpdateMixin, FromNetMixin
  6. from util.observe import ObservableList
  7. from common.actions import action
  8. from common.notifications import fire
  9. from urllib import quote
  10. from util.net import UrlQuery
  11. from traceback import print_exc
  12. import os
  13. import shlex
  14. import locale
  15. from subprocess import Popen
  16. from os.path import expandvars
  17. from logging import getLogger
  18. log = getLogger('emailaccount')
  19. info = log.info
  20. from util import urlprotocol, try_this, get_func_name, call_later, callsback
  21. from path import path
  22. from prefs import localprefprop
  23. import util
  24.  
  25. class EmailAccount(AccountBase, UpdateMixin, FromNetMixin):
  26.     retry_time = 3
  27.     error_max = 3
  28.     
  29.     def __init__(self, enabled = True, updateNow = True, **options):
  30.         AccountBase.__init__(self, **options)
  31.         UpdateMixin.__init__(self, **options)
  32.         FromNetMixin.__init__(self, **options)
  33.         self.emails = ObservableList()
  34.         self.count = 0
  35.         self.seen = set()
  36.         self._dirty_error = True
  37.         log.info('Created EmailAccount: %r. Setting enabled to %r', self, enabled)
  38.         self.enabled = enabled
  39.  
  40.     
  41.     def timestamp_is_time(self, tstamp):
  42.         return True
  43.  
  44.     
  45.     def mailclient_localprefs_key(acct):
  46.         return '/'.join([
  47.             acct.protocol,
  48.             acct.username,
  49.             'mailclient'])
  50.  
  51.     mailclient = localprefprop(mailclient_localprefs_key, None)
  52.     email_address = util.iproperty('get_email_address', 'set_email_address')
  53.     
  54.     def get_email_address(self):
  55.         EmailAddress = EmailAddress
  56.         import util
  57.         
  58.         try:
  59.             return str(EmailAddress(self.name, self.default_domain)).decode('ascii')
  60.         except AttributeError:
  61.             
  62.             try:
  63.                 ret = None if '@' in self.name else self.name + '@' + self.default_domain
  64.                 return str(ret).decode('ascii')
  65.             except Exception:
  66.                 return self.name.decode('ascii', 'replace')
  67.             except:
  68.                 None<EXCEPTION MATCH>Exception
  69.             
  70.  
  71.             None<EXCEPTION MATCH>Exception
  72.  
  73.  
  74.     
  75.     def set_email_address(self, val):
  76.         pass
  77.  
  78.     
  79.     def display_name(self):
  80.         return (try_this,)((lambda : getattr(self, pref('email.display_attr'))), self.email_address)
  81.  
  82.     display_name = property(display_name)
  83.     
  84.     def on_error(self, task = None):
  85.         self.error_count += 1
  86.         log.error("%r's error count is now: %d", self, self.error_count)
  87.         log.error('on_error called from %s', get_func_name(2))
  88.         del self.emails[:]
  89.  
  90.     
  91.     def bad_pw(self):
  92.         log.info('%r: changing state to BAD_PASSWORD', self)
  93.         self.set_offline(self.Reasons.BAD_PASSWORD)
  94.         self.timer.stop()
  95.  
  96.     
  97.     def no_mailbox(self):
  98.         log.info('%r: changing state to NO_MAILBOX', self)
  99.         self.set_offline(self.Reasons.NO_MAILBOX)
  100.         self.timer.stop()
  101.  
  102.     
  103.     def __repr__(self):
  104.         r = AccountBase.__repr__(self)[:-1]
  105.         r += ', '
  106.         None += r if self.enabled else 'disabled'
  107.         return r + '>'
  108.  
  109.     
  110.     def web_login(self):
  111.         if pref('privacy.www_auto_signin'):
  112.             pass
  113.         return self.state in (self.Statuses.ONLINE, self.Statuses.CHECKING)
  114.  
  115.     web_login = property(web_login)
  116.     
  117.     def error_link(self):
  118.         reason = self.Reasons
  119.         linkref = {
  120.             reason.BAD_PASSWORD: (('Edit Account',), (lambda : profile.account_manager.edit(self, True))),
  121.             reason.CONN_FAIL: (('Retry',), (lambda : self.update_now())) }
  122.         if self.offline_reason in linkref:
  123.             (name, callback) = linkref[self.offline_reason]
  124.             return (name, callback)
  125.         else:
  126.             return None
  127.  
  128.     
  129.     def sort_emails(self, new = None):
  130.         self.emails.sort()
  131.         if new is not None:
  132.             new.sort()
  133.         
  134.  
  135.     
  136.     def _received_emails(self, emails, inboxCount = None):
  137.         self.emails[:] = list(emails)
  138.         new = []
  139.         for email in self.emails:
  140.             if email.id not in self.seen:
  141.                 new.append(email)
  142.                 self.seen.add(email.id)
  143.                 continue
  144.         
  145.         self.sort_emails(new)
  146.         info('%s - %s: %d new emails', self.__class__.__name__, self.name, len(new))
  147.         if inboxCount is not None:
  148.             self._setInboxCount(inboxCount)
  149.         
  150.         self.new = new
  151.         if new:
  152.             profile.when_active(self.fire_notification)
  153.         
  154.         self.error_count = 0
  155.         self.change_state(self.Statuses.ONLINE)
  156.         self._dirty_error = True
  157.  
  158.     
  159.     def fire_notification(self):
  160.         if self.new:
  161.             self._notify_emails(self.new)
  162.         
  163.  
  164.     
  165.     def _notify_emails(self, emails, always_show = None, allow_click = True):
  166.         if self.enabled:
  167.             None(fire, email.new = 'emails', emails = 'onclick' if allow_click else None, always_show = always_show, icon = self.icon)
  168.         
  169.  
  170.     
  171.     def _setInboxCount(self, inboxCount):
  172.         self.setnotifyif('count', inboxCount)
  173.  
  174.     
  175.     def OnComposeEmail(self, to = '', subject = '', body = '', cc = '', bcc = '', callback = None):
  176.         for name in ('to', 'subject', 'body', 'cc', 'bcc'):
  177.             pass
  178.         
  179.         if self.mailclient and (try_this,)((lambda : self.mailclient.startswith('file:')), False):
  180.             os.startfile(self.mailclient[5:])
  181.         elif self.mailclient == 'sysdefault':
  182.             kw = { }
  183.             for name in ('subject', 'body', 'cc', 'bcc'):
  184.                 if vars()[name]:
  185.                     kw[name] = vars()[name]
  186.                     continue
  187.             
  188.             query = UrlQuery('mailto:' + quote(to), **kw)
  189.             log.info('OnComposeEmail is launching query: %s' % query)
  190.             os.startfile(query)
  191.         else:
  192.             url = self.compose(to, subject, body, cc, bcc)
  193.             if url:
  194.                 import wx as wx
  195.                 wx.LaunchDefaultBrowser(url)
  196.             
  197.         callback.success()
  198.  
  199.     OnComposeEmail = action()(callsback(OnComposeEmail))
  200.     
  201.     def client_name(self):
  202.         mc = self.mailclient
  203.         if mc in (None, True, False):
  204.             return self.protocol_info().name
  205.         elif mc.startswith('file:'):
  206.             return path(mc).basename().title()
  207.         elif mc == 'sysdefault':
  208.             return ''
  209.         else:
  210.             log.warning('unknown mailclient attribute in %r: %s', self, mc)
  211.             return _('Email Client')
  212.  
  213.     client_name = property(client_name)
  214.     
  215.     def OnClickInboxURL(self, e = None):
  216.         if self.mailclient:
  217.             url = self.start_client_email()
  218.             if url is None:
  219.                 return None
  220.             
  221.         else:
  222.             url = self.inbox_url
  223.         import wx
  224.         wx.LaunchDefaultBrowser(self.inbox_url)
  225.  
  226.     OnClickInboxURL = action()(OnClickInboxURL)
  227.     OnClickHomeURL = OnClickInboxURL
  228.     
  229.     def OnClickEmail(self, email):
  230.         if self.mailclient:
  231.             self.start_client_email(email)
  232.         else:
  233.             import wx
  234.             wx.LaunchDefaultBrowser(self.urlForEmail(email))
  235.         cname = self.__class__.__name__
  236.         if self.web_login and cname not in ('IMAPMail', 'PopMail'):
  237.             self._remove_email(email)
  238.         
  239.  
  240.     
  241.     def OnClickSend(self, to = '', subject = '', body = '', cc = '', bcc = '', callback = None):
  242.         getattr(self, 'send_email', self.OnComposeEmail)(to = to, subject = subject, body = body, cc = cc, bcc = bcc, callback = callback)
  243.  
  244.     OnClickSend = callsback(OnClickSend)
  245.     
  246.     def start_client_email(self, email = None):
  247.         log.info('mailclient: %s', self.mailclient)
  248.         import os.path as os
  249.         if self.mailclient == 'sysdefault':
  250.             launch_sysdefault_email(email)
  251.         elif (try_this,)((lambda : self.mailclient.startswith('file:')), False):
  252.             filename = self.mailclient[5:]
  253.             if os.path.exists(filename):
  254.                 os.startfile(filename)
  255.             else:
  256.                 log.warning('cannot find %s', filename)
  257.         
  258.  
  259.     
  260.     def __len__(self):
  261.         return self.count
  262.  
  263.     
  264.     def __iter__(self):
  265.         return iter(self.emails)
  266.  
  267.     can_has_preview = False
  268.     
  269.     def icon(self):
  270.         skin = skin
  271.         import gui
  272.         try_this = try_this
  273.         import util
  274.         return (None, try_this)((lambda : skin.get('serviceicons.%s' % self.protocol)), None)
  275.  
  276.     icon = property(icon)
  277.     
  278.     def inbox_url(self):
  279.         raise NotImplementedError
  280.  
  281.     inbox_url = property(inbox_url)
  282.     
  283.     def observe_count(self, callback):
  284.         self.add_gui_observer(callback, 'count')
  285.         self.emails.add_gui_observer(callback)
  286.  
  287.     
  288.     def unobserve_count(self, callback):
  289.         self.remove_gui_observer(callback, 'count')
  290.         self.emails.remove_gui_observer(callback)
  291.  
  292.     
  293.     def observe_state(self, callback):
  294.         self.add_gui_observer(callback, 'enabled')
  295.         self.add_gui_observer(callback, 'state')
  296.  
  297.     
  298.     def unobserve_state(self, callback):
  299.         self.remove_gui_observer(callback, 'enabled')
  300.         self.remove_gui_observer(callback, 'state')
  301.  
  302.     
  303.     def header_funcs(self):
  304.         return [
  305.             ('Inbox', self.OnClickInboxURL),
  306.             ('Compose', self.OnComposeEmail)]
  307.  
  308.     header_funcs = property(header_funcs)
  309.     
  310.     def _get_options(self):
  311.         opts = UpdateMixin.get_options(self)
  312.         return opts
  313.  
  314.     
  315.     def update_info(self, **info):
  316.         flush_state = False
  317.         self.frozen().__enter__()
  318.         
  319.         try:
  320.             for k, v in info.iteritems():
  321.                 if k in ('password', 'username', 'server') and getattr(self, k, None) != v:
  322.                     flush_state = True
  323.                 
  324.                 self.setnotifyif(k, v)
  325.         finally:
  326.             pass
  327.  
  328.         profile.update_account(self)
  329.         if flush_state:
  330.             log.info('Resetting state for %r', self)
  331.             self._reset_state()
  332.         
  333.         self._dirty_error = True
  334.  
  335.     
  336.     def _reset_state(self):
  337.         return NotImplemented
  338.  
  339.     
  340.     def update(self):
  341.         if self.update == EmailAccount.update:
  342.             log.warning('not implemented: %s.update', self.__class__.__name__)
  343.             raise NotImplementedError
  344.         
  345.         if not self.enabled:
  346.             return None
  347.         
  348.         log.info('%s (%s) -- preparing for update. update called from: %s', self, self.state, get_func_name(2))
  349.         if self.state == self.Statuses.OFFLINE:
  350.             self.change_state(self.Statuses.CONNECTING)
  351.         elif self.state == self.Statuses.ONLINE:
  352.             self.change_state(self.Statuses.CHECKING)
  353.         elif self.state == self.Statuses.CONNECTING:
  354.             if not self.error_count:
  355.                 log.error('%s -- called update while connecting, and no errors! disconnecting...', self)
  356.                 self.set_offline(self.Reasons.CONN_FAIL)
  357.             
  358.         else:
  359.             log.error('Unexpected state for update: %r', self.state)
  360.  
  361.     
  362.     def update_now(self):
  363.         netcall(self.update)
  364.         self.timer.reset(self.updatefreq)
  365.  
  366.     update_now = action((lambda self: self.state != self.Statuses.CHECKING))(update_now)
  367.     
  368.     def tell_me_again(self):
  369.         if self.emails:
  370.             emails = self.emails
  371.             allow_click = True
  372.         else:
  373.             Email = Email
  374.             import mail.emailobj
  375.             emails = [
  376.                 Email(id = -1, fromname = _('No unread mail'))]
  377.             allow_click = False
  378.         self._notify_emails(emails, always_show = [
  379.             'Popup'], allow_click = allow_click)
  380.  
  381.     tell_me_again = action()(tell_me_again)
  382.     
  383.     def auth(self):
  384.         netcall(self.authenticate)
  385.  
  386.     auth = action()(auth)
  387.     
  388.     def Connect(self):
  389.         self.change_reason(self.Reasons.NONE)
  390.         call_later(1.5, self.update)
  391.  
  392.     
  393.     def compose(self, to, subject, body, cc, bcc):
  394.         raise NotImplementedError
  395.  
  396.     compose = action()(compose)
  397.     
  398.     def urlForEmail(self, email):
  399.         raise NotImplementedError
  400.  
  401.     
  402.     def open(self, email_message):
  403.         if type(self) is EmailAccount:
  404.             raise NotImplementedError
  405.         
  406.  
  407.     open = action()(open)
  408.     
  409.     def _remove_email(self, email_message):
  410.         
  411.         try:
  412.             self.emails.remove(email_message)
  413.         except ValueError:
  414.             pass
  415.  
  416.         self.setnotifyif('count', self.count - 1)
  417.  
  418.     
  419.     def markAsRead(self, email_message):
  420.         self._remove_email(email_message)
  421.  
  422.     markAsRead = action()(markAsRead)
  423.     
  424.     def delete(self, email_message):
  425.         self._remove_email(email_message)
  426.  
  427.     delete = action()(delete)
  428.     
  429.     def archive(self, email_message):
  430.         self._remove_email(email_message)
  431.  
  432.     archive = action()(archive)
  433.     
  434.     def reportSpam(self, email_message):
  435.         self._remove_email(email_message)
  436.  
  437.     reportSpam = action()(reportSpam)
  438.  
  439. import re
  440. env_re = re.compile('(%.*?%)')
  441.  
  442. def mailclient_error():
  443.     fire('error', title = _('No System Email Client'), msg = _('No system email client is configured.'), details = '')
  444.  
  445.  
  446. def mailclient_launch_error(msg):
  447.     fire('error', title = _('Error launching system mail client'), msg = msg, details = '')
  448.  
  449.  
  450. def envexpand(s):
  451.     parts = env_re.split(s)
  452.     out = []
  453.     for part in parts:
  454.         if part.startswith('%') and part.endswith('%'):
  455.             part = '${' + part[1:-1] + '}'
  456.         
  457.         out.append(part)
  458.     
  459.     return expandvars(''.join(out))
  460.  
  461.  
  462. def launch_sysdefault_email(email = None):
  463.     import wx
  464.     if 'wxMSW' in wx.PlatformInfo:
  465.         is_vista = is_vista
  466.         import gui.native.win.winutil
  467.         if is_vista():
  468.             return launch_sysdefault_email_vista(email)
  469.         
  470.     
  471.     mailclient = urlprotocol.get('mailto')
  472.     log.info('mail client is %r', mailclient)
  473.     if not mailclient.strip():
  474.         mailclient_error()
  475.         return False
  476.     
  477.     mailclient = envexpand(mailclient)
  478.     
  479.     try:
  480.         args = shlex.split(mailclient.encode(locale.getpreferredencoding()))
  481.         args = args[:1]
  482.         log.info('launching %r', args)
  483.         if Popen(args):
  484.             return True
  485.     except Exception:
  486.         e = None
  487.         print_exc()
  488.         msg = e.message
  489.  
  490.     
  491.     try:
  492.         msg = _('Could not start system mail client %r.') % mailclient
  493.     except Exception:
  494.         msg = _('Could not start system mail client.')
  495.         print_exc()
  496.  
  497.     mailclient_launch_error(msg)
  498.  
  499.  
  500. def launch_sysdefault_email_vista(email = None):
  501.     import _winreg as reg
  502.     
  503.     try:
  504.         key = reg.OpenKey(reg.HKEY_CURRENT_USER, 'Software\\Clients\\mail', 0, reg.KEY_READ)
  505.         (client_name, t) = reg.QueryValueEx(key, None)
  506.         log.info('canonical name for mail client: %r', client_name)
  507.         mc_key_name = 'SOFTWARE\\Clients\\Mail\\%s\\shell\\open\\command'
  508.         mc_key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, mc_key_name % client_name, 0, reg.KEY_READ)
  509.         (program, t) = reg.QueryValueEx(mc_key, None)
  510.         log.info('mail client shell launch string: %r', program)
  511.     except Exception:
  512.         e = None
  513.         print_exc()
  514.         return mailclient_error()
  515.  
  516.     if isinstance(program, unicode):
  517.         import sys as sys
  518.         program = program.encode(sys.getfilesystemencoding())
  519.     
  520.     
  521.     try:
  522.         program = envexpand(program)
  523.         import subprocess as subprocess
  524.         import shlex
  525.         args = shlex.split(program)
  526.         log.info('launching vista mail client: %r', args)
  527.         subprocess.Popen(args)
  528.         return True
  529.     except Exception:
  530.         e = None
  531.         print_exc()
  532.         mailclient_launch_error(_('Could not start system mail client.'))
  533.  
  534.  
  535. if __name__ == '__main__':
  536.     launch_sysdefault_email_vista()
  537.  
  538.